/**
 * @file   MultigridSolver.h
 * @author HirasawaYui <yui@Ubuntu18-04>
 * @date   Tue Oct 27 21:01:39 2020
 * 
 * @brief  solve 2D possion equation by multigrid method on domain [0,1]x[0,1].
 *         Finite element method.
 * 
 */

#include "FEMSpace.h"
#include "RestrictionOperator.h"
#include "InterpolationOperator.h"
#include <fstream>
#include <string>
#include <algorithm>
#include <math.h>

class MultigridSolver
{
private:
    /// the total level of multigrid method
    int _n;
    /// the length of each unit
    double _h;
    /// The count of dofs in each row;
    int _SdLen;
    /// the collection of right side
    std::vector<std::vector<double> > _f;
    /// the collection of approximate solution
    std::vector<std::vector<double> > _v;
    /// the level where MG is proceeding now
    int _nowlevel = 1;
    /// the pointer of restriction operator
    RestrictionOperator* _pRestrictOP;
    /// the pointer of interation operator
    InterpolationOperator* _pInterpolateOP;
    /// the weight of WeightedJacobi
    double _w;
    /// the times of Pre-smoothing
    int _PreSmth;
    /// the times of Post-smoothing
    int _PostSmth;
    /// the keywords of cycle type
    std::string _TypeofCycle;
    /// the mark whether this node is boundary
    std::vector<int> _BndMark;
    /// the bottom boundary condition
    std::vector<double> _BtmBnd;
    /// the real solution
    double (*_RealSltn) (double, double);
    /// the right side function
    double (*_func) (double, double);
    FEMSpace _FEM;

public:
    MultigridSolver();
    MultigridSolver(int n, double(*func)(double, double), double(*RS)(double, double), int Pre = 10, int Post = 10, double w = 2.0/3);
    int CortoIdx(int i, int j);
    std::vector<int> IsBoundary();
    void UpdateData();
    void WeightedJacobi(StiffMat A);
    void BottomSolve();
    void VCycle(int StartLevel);
    void FMG();
    double RE_2norm();
    double RE_maxnorm();
    void Solve();
    std::vector<double> ReturnSolution();
    void WriteMatlabData();
};
